package org.zjt.demo.util;

import com.squareup.okhttp.*;
import okio.BufferedSink;

import java.io.File;
import java.io.IOException;
import java.net.Proxy;
import java.nio.file.Files;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

/**
 * Created by zhang on 2017/3/2.
 *
 * OkHttp 发送http请求的工具类
 *
 */
@SuppressWarnings("all")
public class OkHttpUtil {

    private static final String PRE_TMEP_DIR="cache";
    private static final long CACHE_SIZE = 1 << 20L;
    private static final String MEDIA_TYPE ="text/plain";

    //content_Type
    private static final String XML_CONTENT_TYPE ="application/xml";
    private static final String JSON_CONTENT_TYPE ="application/json";
    private static final String HTML_CONTENT_TYPE ="application/x-www-form-urlencoded";




    /**
     * http同步get方法
     * @param url 发送的url
     * @param parameter  参数(?name=zhangsan&age=16)
     * @return
     * @throws IOException
     */
    public static Response SyncGet(String url,String parameter)throws IOException{
        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new OkHttpInterceptor());
        System.out.println(String.format("SyncGet 请求的url:%s",url+parameter));
        Request request = new Request.Builder().url(url+parameter).build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful())
            throw new IOException("服务器端错误: " + response);
        /*
        Headers responseHeaders = response.headers();
        for (int i = 0; i < responseHeaders.size(); i++)
            System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
        System.out.println(response.body().string());
        */
        return response;
    }



    /**
     * http同步Post方法
     * @param url 发送的url
     * @param parameter  参数(name=zhangsan&age=16)
     * @return
     * @throws IOException
     */
    public static Response SyncPost(String url,String parameter)throws IOException{
        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new OkHttpInterceptor());
        MediaType MEDIA_TYPE_TEXT = MediaType.parse(MEDIA_TYPE);
        Request request = new Request.Builder().url(url)
                .post(RequestBody.create(MEDIA_TYPE_TEXT,parameter ))
                .build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful())
            throw new IOException("服务器端错误: " + response);
        return response;
    }


    /**
     * 上传文件
     * @param url   提交的url
     * @param file  提交的文件
     * @param fileName  保存的文件名
     * @return
     * @throws IOException
     */
    public static Response SyncMultipart(String url,File file,String fileName)throws IOException{
        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new OkHttpInterceptor());
        MediaType MEDIA_TYPE_TEXT = MediaType.parse(MEDIA_TYPE);
        RequestBody requestBody = new MultipartBuilder()
                .type(MultipartBuilder.FORM)
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"title\""),
                        RequestBody.create(null, fileName))
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"file\""),
                        RequestBody.create(MEDIA_TYPE_TEXT,file))
                .build();

        Request request = new Request.Builder().url(url).post(requestBody).build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful())
            throw new IOException("服务器端错误: " + response);
        return response;
    }


    /**
     * 可缓存调用结果的http请求
     * @param url   请求的url
     * @param parameter 参数
     * @return
     * @throws IOException
     */
    public static Response SysCacheResponse(String url,String parameter)throws IOException{
        File cacheDirectory = Files.createTempDirectory(PRE_TMEP_DIR).toFile();
        Cache cache = new Cache(cacheDirectory, CACHE_SIZE);
        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new OkHttpInterceptor());
        client.setCache(cache);
        Request request = new Request.Builder().url(url+parameter).build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful())
            throw new IOException("服务器端错误: " + response);
        System.out.println(response.cacheResponse());
        System.out.println(response.networkResponse());
        return response;
    }



    /**
     * 代授权的请求
     * @param url   请求url
     * @param parameter 参数
     * @param user  用户名
     * @param password  密码
     * @return
     * @throws IOException
     */
    public static Response SysAuthenticatorPost(String url,String parameter,final String user ,final String password)throws IOException{
        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new OkHttpInterceptor());
        client.setAuthenticator(new Authenticator() {
            public Request authenticate(Proxy proxy, Response response) throws IOException {
                //Basic+用户名：密码 的base64编码
                String credential = Credentials.basic(user, password);
                return response.request().newBuilder().header("Authorization", credential).build();
            }
            public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
                return null;
            }
        });
        MediaType MEDIA_TYPE_TEXT = MediaType.parse(MEDIA_TYPE);
        Request request = new Request.Builder().url(url)
                .post(RequestBody.create(MEDIA_TYPE_TEXT,parameter ))
                .build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful())
            throw new IOException("服务器端错误: " + response);
        return response;
    }


    /**
     * 实现：线程池，多个线程去发送异步的请求，然后await，当得到结果时候countdown。唤醒线程。
     * 非主线程调用。开多线程去一步调用发送（downLatch初始化为1）
     * @param url   访问的url
     * @param parameter 参数
     * @param downLatch 初始化为1，作为触发器
     * @return
     * @throws IOException
     */
    public static Response AsyncGet(String url, String parameter, final CountDownLatch downLatch)throws IOException{
        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new OkHttpInterceptor());
        Request request = new Request.Builder().url(url).build();
        final Response response=null;
        client.newCall(request).enqueue(new Callback() {
            public void onFailure(Request request, IOException e) {
                downLatch.countDown();
                e.printStackTrace();
            }

            public void onResponse(Response response) throws IOException {
                if (!response.isSuccessful())
                    throw new IOException("服务器端错误: " + response);
                downLatch.countDown();
                System.out.println(response.body().string());
            }
        });
        return response;
    }





    /**
     * 流式post提交
     * @param url
     * @param parameter
     * @return
     * @throws IOException
     */
    public static Response SysPostStream(String url,final String parameter)throws IOException{
        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new OkHttpInterceptor());
        final MediaType MEDIA_TYPE_TEXT = MediaType.parse(MEDIA_TYPE);
        RequestBody requestBody = new RequestBody() {
            @Override
            public MediaType contentType() {
                return MEDIA_TYPE_TEXT;
            }
            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                sink.writeUtf8(parameter);
            }
            @Override
            public long contentLength() throws IOException {
                return parameter.length();
            }
        };

        Request request = new Request.Builder().url(url).post(requestBody).build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful())
            throw new IOException("服务器端错误: " + response);
        System.out.println(response.body().string());
        return response;
    }






    /**
     * http同步get方法
     * @param url   请求url
     * @param data  参数
     * @return
     * @throws IOException
     */
    public static Response SyncGet(String url, Map<String,Object> data)throws IOException{
        Set<Map.Entry<String,Object>> entrys=data.entrySet();
        StringBuffer stringBuffer =new StringBuffer("?");
        for (Map.Entry<String,Object> entry : entrys )
                stringBuffer.append(String.format("%s=%s&",entry.getKey(),entry.getValue()));
        return SyncGet(url,stringBuffer.substring(0,stringBuffer.length()-1));
    }


    /**
     * http同步get方法
     * @param url   请求url
     * @param data  参数
     * @param setHand   设置http头信息
     * @param addHand   新增http头信息（如cooike）
     * @return
     * @throws IOException
     */
    public static Response SyncGet(String url, Map<String,Object> data,Map<String,Object> setHand,Map<String,Object> addHand)throws IOException{
        Set<Map.Entry<String,Object>> entrys=data.entrySet();
        StringBuffer stringBuffer =new StringBuffer("?");
        for (Map.Entry<String,Object> entry : entrys )
            stringBuffer.append(String.format("%s=%s&",entry.getKey(),entry.getValue()));
        return SyncGet(url,stringBuffer.substring(0,stringBuffer.length()-1),setHand,addHand);
    }


    /**
     * http同步get方法
     * @param url   请求url
     * @param parameter  参数
     * @param setHand   设置http头信息
     * @param addHand   新增http头信息（如cooike）
     * @return
     * @throws IOException
     */
    public static Response SyncGet(String url,String parameter,Map<String,Object> setHand,Map<String,Object> addHand)throws IOException{
        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new OkHttpInterceptor());
        System.out.println(String.format("SyncGet 请求的url:%s",url+parameter));
        Request.Builder requestBuild = new Request.Builder().url(url+parameter);

        //覆盖http头信息
        Set<Map.Entry<String,Object>> entrys=setHand.entrySet();
        for (Map.Entry<String,Object> entry : entrys )
            requestBuild.header(entry.getKey(),String.valueOf(entry.getValue()));

        //新增http头信息
        entrys=addHand.entrySet();
        for (Map.Entry<String,Object> entry : entrys )
            requestBuild.addHeader(entry.getKey(),String.valueOf(entry.getValue()));

        Request request=requestBuild.build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful())
            throw new IOException("服务器端错误: " + response);
        /*
        Headers responseHeaders = response.headers();
        for (int i = 0; i < responseHeaders.size(); i++)
            System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
        System.out.println(response.body().string());
        response.headers("Set-Cookie")   得到cookie信息
        */
        return response;
    }


    /**
     *  okHttp请求拦截类
     */
    static class OkHttpInterceptor  implements Interceptor {
        public Response intercept(Chain chain) throws IOException {

            //记录发送
            Request request = chain.request();
            long t1 = System.nanoTime();
            System.out.println(String.format("发送请求: [%s] %s%n%s", request.url(), chain.connection(), request.headers()));

            //处理响应
            Response response = chain.proceed(request);
            long t2 = System.nanoTime();
            System.out.println(String.format("接收响应: [%s] %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers()));

            return response;
        }
    }


    public static void main(String[] args)throws IOException  {

        SyncGet("https://www.baidu.com","?name=zhangsan&age=16");

    }
}
